﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;

using HBFFirmwareGetter.BusinessEntities;
using HBFFirmwareGetter.Properties;
using HBFFirmwareGetter.Helpers;
using System.Text.RegularExpressions;

namespace HBFFirmwareGetter.Code
{
	public static class Core
	{
		#region Private Fields

		private static List<DateTime> _dates = new List<DateTime>();
		private static List<double> _counters = new List<double>();

		private static bool _useProxy;
		private static bool _needAuthorization;

		private static decimal _proxyPort;
		private static string _proxyAddress;
		private static string _login;
		private static string _password;
		private static decimal _timeOut;

		private static decimal _filesPerThread;

		private static double _filesCounter = 0;

		#endregion Private Fields

		#region Public Interface

		public static double FilesCounter
		{
			get { return _filesCounter; }
			set { _filesCounter = value; }
		}

		public static void DoWork(int threadID, ref int count)
		{
			TextWriter tw = new StreamWriter(String.Concat("file", threadID, ".txt"), true, Encoding.ASCII);
			TextWriter exceptions = new StreamWriter(String.Concat("exceptions", threadID, ".txt"), true, Encoding.ASCII);

			foreach (var item in GetResultUrl(threadID))
			{
				try
				{
					WebRequest request = CreateWebRequest(item);

					WebResponse response = request.GetResponse();

					if (response != null && response.ContentLength > 0)
					{
						response.GetResponseStream();

						byte[] buffer = new byte[120];

						response.GetResponseStream().Read(buffer, 0, 120);

						string firmwareName = Encoding.ASCII.GetString(buffer);

						if (OnFirmwareFound != null && !String.IsNullOrEmpty(firmwareName))
						{
							OnFirmwareFound(threadID, new FirmwareFoundEventArgs()
							{
								URL = item,
								FirmwareName = Regex.Match(firmwareName, Constant.PATTERN).Value
							});
						}

						tw.WriteLine("File {0} = {1}, {2}", item.ID, firmwareName, "Yes");
					}

					else
					{
						Console.WriteLine("File {0} = {1}", item.ID, "No");
					}

					if (response != null)
					{
						response.Close();
					}

					count++;
				}

				catch (Exception ex)
				{
					exceptions.WriteLine(String.Concat(ex.Message, " = ", item.URL));
				}

				finally
				{
					_filesCounter++;

					if (OnFileProcessed != null)
					{
						OnFileProcessed(_filesCounter);
					}

					if (count == (_filesPerThread - 1))
					{
						tw.WriteLine("Last File {0}", item.Name);
					}

					tw.Flush();
					exceptions.Flush();
				}
			}
			exceptions.Close();
			tw.Close();
		}

		public static void FillDatesCollection(DateTime startDate)
		{
			_dates.Add(startDate);
		}

		public static void FillCounterCollection(double counter)
		{
			_counters.Add(counter);
		}

		public static void InitializeCore(
			bool useProxy,
			decimal proxyPort,
			string proxyAddress,
			string login,
			string password,
			bool needAuthorization,
			decimal timeOut,
			decimal filesPerThread)
		{
			_useProxy = useProxy;
			_proxyPort = proxyPort;
			_proxyAddress = proxyAddress;
			_login = login;
			_password = password;
			_needAuthorization = needAuthorization;
			_timeOut = timeOut;
			_filesPerThread = filesPerThread;
		}

		#endregion Public Interface

		#region Events

		public delegate void FirmwareFoundEventHandler(object sender, FirmwareFoundEventArgs e);
		public delegate void FileProcessedEventHandler(object sender);

		public static event FirmwareFoundEventHandler OnFirmwareFound;
		public static event FileProcessedEventHandler OnFileProcessed;

		#endregion Events

		#region Internal Implementation

		/// <summary>
		/// Creates the web request, and fill its properties.
		/// </summary>
		/// <param name="url">The URL.</param>
		/// <returns>Web request.</returns>
		private static WebRequest CreateWebRequest(FirmwareURL url)
		{
			WebRequest request = HttpWebRequest.Create(url.URL);

			if (_useProxy)
			{
				WebProxy myproxy = new WebProxy(_proxyAddress, (int)_proxyPort);

				if (_needAuthorization)
				{
					myproxy.Credentials = CredentialCache.DefaultCredentials;
				}

				else
				{
					myproxy.Credentials =
						new NetworkCredential(_login, _password);
				}

				myproxy.BypassProxyOnLocal = false;

				request.Proxy = myproxy;
			}

			request.Timeout = (int)_timeOut;

			return request;
		}

		private static HashSet<FirmwareURL> GetResultUrl(int threadID)
		{
			double startIndex = _counters[threadID];

			HashSet<FirmwareURL> resultURLs = new HashSet<FirmwareURL>();

			for (int i = 0; i < _filesPerThread; i++)
				{
					FirmwareURL url = new FirmwareURL();

					url.ID = startIndex.ToString();
					url.Name = String.Concat(startIndex.ToString(), Constant.RESULT_FILE_EXTENSION);
					url.URL = String.Format(Settings.Default.URLFormatString, url.ID, url.Name);

					resultURLs.Add(url);

					startIndex += i;
				}
	

			return resultURLs;
		}

		#endregion Internal Implementation
	}
}
